package com.enki.cigarettes.controller;

import com.alibaba.fastjson.JSONObject;
import com.enki.cigarettes.controller.vo.request.WechatRequestVo;
import com.enki.cigarettes.entity.UserT;
import com.enki.cigarettes.handler.Response;
import com.enki.cigarettes.redis.RedisBaseOperation;
import com.enki.cigarettes.repository.UserTRepository;
import com.enki.cigarettes.statics.StaticKeys;
import com.enki.cigarettes.utils.DateUtils;
import com.enki.cigarettes.utils.PrimaryKey;
import com.enki.cigarettes.utils.wechat.AesCbcUtil;
import com.enki.cigarettes.utils.wechat.WechatConfig;
import com.enki.cigarettes.utils.wechat.WechatUtil;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;
import java.util.Date;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author WCS.Wang
 * @version V1.0
 * @Package com.enki.cigarettes.controller
 * @Name e-cigarettes-shop-api-module
 * @Description: TODO (用一句话描述该文件做什么)
 * @date 2019-07-30
 */
@RestController
@RequestMapping("/api")
@Slf4j
public class RequestController {

    @Autowired
    UserTRepository userTRepository;
    @Autowired
    WechatConfig wechatConfig;
    @Autowired
    RedisBaseOperation<String> stringRedisBaseOperation;

    @ApiOperation(value = "微信登录凭证")
    @PostMapping
    public Object request(@RequestBody WechatRequestVo item, HttpSession session) {
        try {
            if (StringUtils.isBlank(item.getCode())) {
                return Response.badRequest_400("未获取到用户凭证");
            }
            String requestUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + wechatConfig.getAppid() + "&secret=" + wechatConfig.getAppsecret() + "&js_code=" + item.getCode() + "&grant_type=authorization_code";
            JSONObject jsonObject = WechatUtil.httpsRequest(requestUrl, "GET", null);
            log.info("jsonObject：" + jsonObject);
            String sessionKey = jsonObject.get("session_key").toString(); //会话秘钥
            String openid = jsonObject.get("openid").toString(); //用户唯一标识
            UserT user = userTRepository.findOneByOpenidAndUserSource(openid, item.getUserSource());
            if (user == null) {
                JSONObject userInfoJSONObject = AesCbcUtil.decrypt(item.getEncryptedData(), sessionKey, item.getIv(), "UTF-8");
                UserT bean = new UserT();
                bean.setId(PrimaryKey.get().toString());
                bean.setPassword(StaticKeys.NULL);
                bean.setNickname(filterEmoJi(userInfoJSONObject.get("nickName").toString()));
                bean.setPhone(StaticKeys.NULL);
                bean.setEmail(StaticKeys.NULL);
                bean.setUserType(0);
                bean.setCurWelfare(0);
                bean.setCurBalance(0);
                bean.setCurIntegral(0);
                bean.setCurGrow(0);
                bean.setGender(userInfoJSONObject.getInteger("gender"));
                bean.setMarriage(0);
                bean.setIncome(0);
                bean.setRealname(StaticKeys.NULL);
                bean.setIdCard(StaticKeys.NULL);
                bean.setEducation(0);
                bean.setIndustry(0);
                bean.setHeadPortrait(userInfoJSONObject.get("avatarUrl").toString());
                bean.setPreference(StaticKeys.NULL);
                bean.setBirthday(DateUtils.getDateYMD(new Date()));
                bean.setProvince(userInfoJSONObject.get("province").toString());
                bean.setCity(userInfoJSONObject.get("city").toString());
                bean.setInvitationCode(generateNumber());
                bean.setOpenid(jsonObject.get("openid").toString());
                bean.setInviteeCode(item.getInvitationCode());
                // 注册来源，0为中文、1为英文
                bean.setUserSource(item.getUserSource());
                bean.setCreateTime(new Date());
                userTRepository.save(bean);
                session.setAttribute(StaticKeys.USER_ID, bean.getId());
                return Response.success();
            } else {
                JSONObject userInfoJSONObject = AesCbcUtil.decrypt(item.getEncryptedData(), sessionKey, item.getIv(), "UTF-8");
                user.setHeadPortrait(userInfoJSONObject.get("avatarUrl").toString());
                userTRepository.save(user);
                session.setAttribute(StaticKeys.USER_ID, user.getId());
                return Response.success();
            }

        } catch (Exception e) {
            log.error("获取用户信息失败：" + e.getMessage());
            e.printStackTrace();
            return Response.serverError_500("获取用户信息失败");
        }
    }


    /*
     * 这是典型的随机洗牌算法。 流程是从备选数组中选择一个放入目标数组中，将选取的数组从备选数组移除（放至最后，并缩小选择区域） 算法时间复杂度O(n)
     *
     * @return 随机6为不重复数组
     */
    public String generateNumber() {
        String no = "";
        // 初始化备选数组
        String[] defaultNums = new String[]{"A", "B", "C", "D", "E", "F", "G", "Q", "W", "E", "R", "T", "Y", "U", "P",
                "S", "H", "J", "K", "L", "Z", "X", "V", "N", "M", "2", "3", "4", "5", "6", "7", "8", "9"};

        Random random = new Random(UUID.randomUUID().hashCode());
        String[] nums = new String[LENGTH];
        // 默认数组中可以选择的部分长度
        int canBeUsed = defaultNums.length;
        // 填充目标数组
        for (int i = 0; i < nums.length; i++) {
            // 将随机选取的数字存入目标数组
            int index = random.nextInt(canBeUsed);
            nums[i] = defaultNums[index];
            // 将已用过的数字扔到备选数组最后，并减小可选区域
            swap(index, canBeUsed - 1, defaultNums);
            canBeUsed--;
        }
        if (nums.length > 0) {
            for (int i = 0; i < nums.length; i++) {
                no += nums[i];
            }
        }
        UserT user = userTRepository.findOneByInvitationCode(no);
        if (user == null) {
            return no;
        } else {
            generateNumber();
        }
        return no;
    }

    private static final int LENGTH = 6;

    private void swap(int i, int j, String[] defaultNums) {
        String temp = defaultNums[i];
        defaultNums[i] = defaultNums[j];
        defaultNums[j] = temp;
    }


    /**
     * 过滤emoji 或者 其他非文字类型的字符
     *
     * @param source
     * @return
     */
    public static String filterEmoJi(String source) {
        if (StringUtils.isBlank(source)) {
            return source;
        }
        StringBuilder buf = null;
        int len = source.length();
        for (int i = 0; i < len; i++) {
            char codePoint = source.charAt(i);
            if (isEmojiCharacter(codePoint)) {
                if (buf == null) {
                    buf = new StringBuilder(source.length());
                }
                buf.append(codePoint);
            }
        }
        if (buf == null) {
            return source;
        } else {
            if (buf.length() == len) {
                buf = null;
                return source;
            } else {
                return buf.toString();
            }
        }
    }

    private static boolean isEmojiCharacter(char codePoint) {
        return (codePoint == 0x0) || (codePoint == 0x9) || (codePoint == 0xA)
                || (codePoint == 0xD)
                || ((codePoint >= 0x20) && (codePoint <= 0xD7FF))
                || ((codePoint >= 0xE000) && (codePoint <= 0xFFFD))
                || ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF));
    }
}
